מבני נתונים ואלגוריתמים תרגול #3 נושאים: תור קדימויות/ערימה, עצים חזרה מבנה נתונים אמצעי לאחסון נתונים במחשב. יש הרבה סוגים שונים, וצריך להשתמש במבנה שהכי מתאים לבעיה שלנו מבחינת שימוש בנתונים הוספה, מחיקה וחיפוש. צריך לשים שיש מבני נתונים מופשטים type) (ADT abstract data שמגדירים ממשק מסוים ללא מימוש. למשל, מחסנית הוא מבנה נתונים מופשט, שניתן לממש באמצעות תור או רשימה מקושרת (שהם גם מבני נתונים). מערך הכנסה/הוצאה,O(n) גישה (1)O, מוגבל במקום. רשימה מקושרת הכנסה/הוצאה (1)O, גישה,O(n) לא מוגבל במקום. רשימה דומקושרת יש גם מצביע לאיבר הקודם. מחסנית Out).(Last In First מימוש באמצעות מערך: כל הפעולות (1)O. אם נגמר המקום, צריך להכפיל את גודל המערך ולהעתיק הכל,לוקח.O(n) מימוש באמצעות רשימה מקושרת: כל הפעולות (1)O. אם רוצים לרוקן את המחסנית, צריך לשחרר את כל ההקצאות הדינמיות, לוקח.O(n) תור Out).(First In First מימוש באמצעות מערך: מכיוון שכל הזמן מכניסים איברים, התור "זז" וזה מבזבז מקום. לכן נתייחס למערך כמעגל. מימוש באמצעות רשימה מקושרת: תור עדיפויות/ערימה הרעיון כמו תור רגיל, אך מחזיקים בנוסף ערך שמתאר את העדיפות של הנתון. לדוגמא Scheduler של תוכניות במחשב. מימושים נאיביים: מכניסים את האיברים לפי הסדר (כמו תור רגיל), וכאשר מוצאים איבר מחפשים את האיבר עם הקדימות הגבוהה ביותר. הכנסה (1)O, הוצאה.O(n) מכניסים את האיברים לפי הקדימויות. הכנסה,O(n) הוצאה (1)O. (1 (2 מימוש נוסף: אם יש מספר קטן של קדימויות, ניתן ליצור תור עבור כל קדימות, ונוציא איבר מהתור בעל הקדימות הגבוהה ביותר. מימוש יעיל יותר ערימה.Heap ערימה מערך שניתן לראות כעף בינארי כמעט מלא (=עץ בינארי שבו כל הרמות מלאות פרט אולי לרמה האחרונה, שמלאה מצד שמאל עד לנקודה מסוימת). דוגמא לערימת מקסימום ] 1 [ 17 14 10 8 7 9 3 2 4 = A
"תכונת הערימה" חייבת להתקיים : A[i] A[Parent(i)] (ערימת מקימום). בהקשר של תור קדימויות הערכים הם הקדימויות. מציאת ערכים: בהינתן אינדקס i של צומת:.2i + 1 בן ימני,2i בן שמאלי, אבא.log n גובה העץ מימוש: יותר נוח למלא את המערך מאינדקס 1. תריך מצביע לאיבר האחרון במערך.end פעולות בערימה: Heapsize מספר האיברים בערימה. Create (n): A array of size n end = 0; Push (x): A[end++] = x; i = end; while i>1 and A[i]>A[Parent(i)] k = A[Parent(i)]; switch(a[i],a[k]); i=k; x = Pop(): if end==0 error(empty) else x=a[i]; A[1]=A[end]; end; Heapify(1); return x;
Heapify(i): l = Left(i); r = Right(i); if l heapsize and A[l] >A[i] max = l; if r heapsize and A[r] >A[max] max = r; if max i switch( A[i],A[max]) Heapify(max); תרגיל: נתונות k רשימות ממוינות באורך n. מזגו את הרשימות לרשימה אחת ממויינת ב( k.θ(nk log פיתרון: כלומר רוצים למצוא את בכל צעד רוצים למצוא את האיבר הקטן ביותר ולהכניס למערך הפלט. נחזיק k אינדקסים (אחד לכל רשימה). כל פעם נמצא כל פעם נמצא את r כך ש ] L [i ] = min {, } L [i הרשימה שהאיבר הראשון בה הכי קטן. L,, L הן הרשימות, L היא הרשימה הממוזגת ו i הוא האיבר הנוכחי שמוסיפים. H heap of pairs (list index + number) L array of size nk i = i = i = = i = 0 for j=1 to k: Ο H.Push(L i, j) While H.IsEmpty==false (a,j) = H.Pop(); L [i ] = a; Ο(nk log k) i + +; i + +; if i < n H.Push(L i, j) האלגוריתם: אם היינו מוצאים את i ע"י מעבר על כל הרשימות, הסיבוכיות הייתה ).Ο(nk עצים נושאים: עצי חיפוש עצים מאוזני גובה: עצי 23 ועצי AVL הגדרות:
עץ בינארי: עץ שבו לכל צומת יש לכל היותר 2 בנים. עץ בינארי מלא: עץ בינארי בו לכל צומת פנימי יש בדיוק 2 בנים. עץ בינארי שלם: עץ בינארי בו כל העלים באותו עומק. עץ בינארי כמעט שלם: עץ שלם שהוצאו ממנו עלים מצד ימין. תכונות של עץ בינארי שלם: ) n צמתים, L עלים וגובה h) מספר צמתים בעומק n = 2 :i מספר עלים: L = n = 2 n = מספר צמתים בעץ: 1 n = 2 = 2 גובה של העץ n) h = log (n + 1) 1 = O(log עצי חיפוש עץ בינארי שבו מתקיים הכלל הבא: X צומת בעץ חיפוש בינארי. אם y הוא צומת בתתהעץ השמאלי של x מתקיים ש y x. אם y הוא צומת בתתהעץ הימני של x מתקיים ש x y. > דוגמא מעברים בעץ: :Preorder בקר בשורש, סייר בתתהעץ השמאלי, סייר בתתהעץ הימני. :Postorder סייר בתתהעץ השמאלי, סייר בתתהעץ הימני, בקר בשורש. :Inorder סייר בתתהעץ השמאלי, בקר בשורש, סייר בתתהעץ הימני. תרגיל: מספרו את הצמתים לפי הסדר שלהם בעץ החיפוש:
פיתרון: מעבר inorder על העץ: D, B, H, E, A, F, C, K, I G, J פעולות בעץ חיפוש: חיפוש: בצורה רקורסיבית אם הערך קטן ממה שמחפשים, לך שמלאה. אחרת ימינה. הכנסה: בצורה איטרטיבית סורקים עד למטה (עד שמגיעים ל null ) ומוסיפים. המחיקה: 3 מצבים אין לצומת בנים מוחקים, לצומת יש בן יחיד יוצרים קשת בין הבן לאב ומוחקים. יש לצומת 2 בנים מוחקים את הערך הקודם לו (הכי ימני בתת העץ השמאלי) ומחליפים ערכים ביניהם. (1 (2 (3 דוגמא (בעץ הראשון): הוסף 0.5, 1.5 מחק 8 מחק 7 מחק 1 סיבוכיות הפעולות O(logn) (כאשר העץ מאוזן). אם לא שומרים על איזון נקבל רשימה לינארית והחיפוש ייקח.O(n) פיתרון עץ מאוזן גובה רוצים שההפרש בין עומק 2 תתי עצים יהיה לכל היותר 1. עצי 23 כל העלים באותה רמה
כל הערכים בעלים בצמתים הפנימיים יש אינדקסים לכל צומת פנימי יש 2 או 3 בנים, ומספר תואם של אינדקסים. מספר העלים מקיים h) 2 L 3 גובה העץ) גובה העץ:.h = Θ(logL) log L h log L בעץ 23 מתקיימים התנאים הבאים: בצומת עם 2 בנים: יש אינדקס יחיד שגדול ממש מהערך המקסימלי בתת העץ השמאלי וקטןשווה מהערך המינימלי בתתהעץ הימני. בצומת עם 3 בנים: האינדקס הראשון גדול ממש מהערכים בתתהעץ השמאלי, קטןשווה מהערכים בתתהעץ האמצעי, ואינדקס שני גדול ממש מהערכים בתתהעץ האמצעי וקטן שווה מהערכים בתתהעץ הימני. פעולות בעץ 23: לפי הכללים הנ"ל חיפוש הוספה: חפש את הערך. הוסף אותו לצומת הפנימי האחרון אליו הגעת והוסף אינדקס אם יש 4 בנים פצל והעלה אינדקס אמצעי 2.1. חזור ל 2.1 עבור האב 2.2. מחיקה: חפש את הערך. מחק את הערך ואת האינדקס משמאלו (או הכי שמאלי). אם נשארו 2 בנים סיים. 3.1. אחרת אם לאב יש אח עם 3 בנים השאל בן וסיים. 3.2. אחרת אחד את האב עם אח שלו ועדכן אינדקסים. 3.3. חזור ל 3.1 עבור האב. 3.4. (1 (2 (3 דוגמא: הוסף 7:
הוסף :15 מחק :15 מחק :14
מחק :3